import { Injectable, Logger } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository, DataSource } from "typeorm";
import { CharacterMountEntity } from "../entities/character-mount.entity";
import { MountTrainingEntity } from "../entities/mount-training.entity";
import { MountBaseEntity } from "../entities/mount-base.entity";
import { CharacterEntity } from "../entities/character.entity";
import { CharacterResourcesEntity } from "../entities/character-resources.entity";
import { MountLevelExperienceService } from "./mount-level-experience.service";
import { getMountAttributeConfig, calculateMountAttribute, PROMOTION_MAX_LEVELS } from "../data/mount-attribute-config";

@Injectable()
export class CharacterMountService {
  private readonly logger = new Logger(CharacterMountService.name);

  // 每日训练次数限制
  private readonly DAILY_TRAINING_LIMIT = 20;

  // 训练消耗金币
  private readonly TRAINING_COST = 20;

  // 训练获得经验值：改为按等级查表 (mount_level_experience.exp_per_training)
  private readonly TRAINING_EXP_GAIN = 0;

  constructor(
    @InjectRepository(CharacterMountEntity)
    private readonly characterMountRepository: Repository<CharacterMountEntity>,
    @InjectRepository(MountTrainingEntity)
    private readonly mountTrainingRepository: Repository<MountTrainingEntity>,
    @InjectRepository(MountBaseEntity)
    private readonly mountBaseRepository: Repository<MountBaseEntity>,
    private readonly dataSource: DataSource,
    private readonly mountLevelExperienceService: MountLevelExperienceService
  ) { }

  /**
   * 获取角色的所有坐骑
   */
  async getCharacterMounts(
    characterId: number
  ): Promise<CharacterMountEntity[]> {
    try {
      return await this.characterMountRepository.find({
        where: { characterId },
        relations: ["mountBase"],
        order: { id: "ASC" },
      });
    } catch (error) {
      this.logger.error(`获取角色坐骑失败: characterId=${characterId}`, error);
      throw error;
    }
  }

  /**
   * 获取角色当前出战的坐骑
   */
  async getActiveMount(
    characterId: number
  ): Promise<CharacterMountEntity | null> {
    try {
      return await this.characterMountRepository.findOne({
        where: { characterId, status: 2 }, // 2表示出战状态
        relations: ["mountBase"],
      });
    } catch (error) {
      this.logger.error(`获取出战坐骑失败: characterId=${characterId}`, error);
      throw error;
    }
  }

  /**
   * 根据ID获取玩家坐骑详情
   */
  async getCharacterMountById(
    characterId: number,
    mountId: number
  ): Promise<CharacterMountEntity | null> {
    try {
      return await this.characterMountRepository.findOne({
        where: { id: mountId, characterId },
        relations: ["mountBase"],
      });
    } catch (error) {
      this.logger.error(
        `获取坐骑详情失败: characterId=${characterId}, mountId=${mountId}`,
        error
      );
      throw error;
    }
  }

  /**
   * 训练坐骑
   * 指令: {c:4420, d:{id:坐骑ID, t:"1"}}
   */
  async trainMount(
    characterId: number,
    mountId: number
  ): Promise<{
    success: boolean;
    message: string;
    experienceGained?: number;
    newLevel?: number;
  }> {
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();

    try {
      // 1. 获取坐骑信息
      const mount = await queryRunner.manager.findOne(CharacterMountEntity, {
        where: { id: mountId, characterId },
        relations: ["mountBase"],
      });

      if (!mount) {
        throw new Error("坐骑不存在");
      }

      // 2. 检查今日训练次数
      const today = new Date();
      today.setHours(0, 0, 0, 0);

      let trainingRecord = await queryRunner.manager.findOne(
        MountTrainingEntity,
        {
          where: {
            characterId,
            characterMountId: mountId,
            trainingDate: today,
          },
        }
      );

      if (!trainingRecord) {
        // 创建新的训练记录
        trainingRecord = queryRunner.manager.create(MountTrainingEntity, {
          characterId,
          characterMountId: mountId,
          trainingDate: today,
          dailyCount: 0,
          totalExperience: 0,
        });
      }

      // 3. 检查训练次数限制
      if (trainingRecord.dailyCount >= this.DAILY_TRAINING_LIMIT) {
        throw new Error(
          `今日训练次数已达上限（${this.DAILY_TRAINING_LIMIT}次）`
        );
      }

      // 4. 获取当前等级的训练经验值（按表格）
      const experienceGained = await this.mountLevelExperienceService.getExpPerTraining(mount.level);

      // 经验溢出&升级逻辑：对齐 1208 角色领取经验逻辑（按坐骑经验表）
      let newLevel = mount.level;
      let newExp = parseInt((mount.experience as any).toString()) || 0;
      newExp += experienceGained;

      // 循环处理可能的多级升级
      while (true) {
        const expToNext = await this.mountLevelExperienceService.getExpToNextLevel(newLevel);
        if (!expToNext || expToNext <= 0) break; // 已达上限
        if (newExp >= expToNext) {
          newExp -= expToNext;
          newLevel += 1;
          continue;
        }
        break;
      }
      mount.level = newLevel;
      mount.experience = newExp;
      trainingRecord.dailyCount += 1;
      const currentTotalExp = parseInt(trainingRecord.totalExperience.toString()) || 0;
      trainingRecord.totalExperience = currentTotalExp + experienceGained;

      // 5. 若升级，重新计算属性
      this.updateMountAttributes(mount);

      // 6. 保存数据
      await queryRunner.manager.save(mount);
      await queryRunner.manager.save(trainingRecord);

      await queryRunner.commitTransaction();

      const message = `本次驯养消耗 ${this.TRAINING_COST} 金,获得经验值 ${experienceGained}`;
      return {
        success: true,
        message,
        experienceGained,
        newLevel: mount.level,
      };
    } catch (error: any) {
      await queryRunner.rollbackTransaction();
      this.logger.error(
        `训练坐骑失败: characterId=${characterId}, mountId=${mountId}`,
        error
      );
      return {
        success: false,
        message: error?.message || "训练失败",
      };
    } finally {
      await queryRunner.release();
    }
  }

  /**
   * 设置坐骑状态（出战/休息）
   * 指令: {c:4425, d:{id:坐骑ID, t:状态}}
   * t: 1-休息, 2-出战
   */
  async setMountStatus(
    characterId: number,
    mountId: number,
    status: number
  ): Promise<{ success: boolean; message: string }> {
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();

    try {
      // 验证状态值
      if (status !== 1 && status !== 2) {
        throw new Error("无效的状态值");
      }

      // 获取坐骑信息
      const mount = await queryRunner.manager.findOne(CharacterMountEntity, {
        where: { id: mountId, characterId },
      });

      if (!mount) {
        throw new Error("坐骑不存在");
      }

      // 如果要设置为出战状态，需要先将其他坐骑设置为休息
      if (status === 2) {
        await queryRunner.manager.update(
          CharacterMountEntity,
          { characterId, status: 2 },
          { status: 1 }
        );
      }

      // 设置当前坐骑状态
      mount.status = status;
      await queryRunner.manager.save(mount);

      await queryRunner.commitTransaction();

      const statusText = status === 2 ? "出战" : "休息";
      return {
        success: true,
        message: `坐骑已设置为${statusText}状态`,
      };
    } catch (error: any) {
      await queryRunner.rollbackTransaction();
      this.logger.error(
        `设置坐骑状态失败: characterId=${characterId}, mountId=${mountId}, status=${status}`,
        error
      );
      return {
        success: false,
        message: error?.message || "设置状态失败",
      };
    } finally {
      await queryRunner.release();
    }
  }

  /**
   * 获取当前出战坐骑信息
   * 指令: {c:4419}
   */
  async getActiveMountInfo(characterId: number): Promise<any> {
    try {
      const activeMount = await this.getActiveMount(characterId);

      if (!activeMount) {
        return {
          success: false,
          message: "没有出战的坐骑",
        };
      }

      // 计算升级所需经验
      const expToNextLevel = await this.mountLevelExperienceService.getExpToNextLevel(activeMount.level);

      return {
        success: true,
        data: {
          id: activeMount.id,
          name: activeMount.mountBase.name,
          img: activeMount.mountBase.img,
          lvl: activeMount.level,
          exp: expToNextLevel,
          trans: activeMount.transLevel,
          zz: 0, // 暂时设为0
          ap: activeMount.currentAp,
          hp: activeMount.currentHp,
          mp: activeMount.currentMp,
          sp: activeMount.currentSp,
        },
      };
    } catch (error: any) {
      this.logger.error(
        `获取出战坐骑信息失败: characterId=${characterId}`,
        error
      );
      return {
        success: false,
        message: error?.message || "获取坐骑信息失败",
      };
    }
  }

  /**
   * 购买坐骑
   */
  async purchaseMount(
    characterId: number,
    mountBaseId: number
  ): Promise<{ success: boolean; message: string; mountId?: number }> {
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();

    try {
      // 检查坐骑基础数据是否存在
      const mountBase = await queryRunner.manager.findOne(MountBaseEntity, {
        where: { id: mountBaseId },
      });

      if (!mountBase) {
        throw new Error("坐骑不存在");
      }

      // 检查是否已经拥有该坐骑（每种坐骑只能购买一次）
      const existingMount = await queryRunner.manager.findOne(
        CharacterMountEntity,
        {
          where: { characterId, mountBaseId },
        }
      );

      if (existingMount) {
        throw new Error(`您已经拥有${mountBase.name}，不能重复购买`);
      }

      // 检查玩家金币是否足够
      const characterResources = await queryRunner.manager.findOne(
        CharacterResourcesEntity,
        {
          where: { characterId },
        }
      );

      if (!characterResources) {
        throw new Error("角色资源不存在");
      }

      const currentGold = characterResources.gold;
      const mountPrice = mountBase.price || 0;

      if (currentGold < mountPrice) {
        throw new Error(`您的金不足${mountPrice}不能领取${mountBase.name}`);
      }

      // 扣除金币
      const newGold = currentGold - mountPrice;
      await queryRunner.manager.update(
        CharacterResourcesEntity,
        { characterId },
        { gold: newGold }
      );

      // 创建新坐骑
      const newMount = queryRunner.manager.create(CharacterMountEntity, {
        characterId,
        mountBaseId,
        level: 1,
        experience: 0,
        transLevel: 0,
        status: 1, // 默认休息状态
        mountBase: mountBase, // 设置关联数据
      });

      // 计算初始属性
      this.updateMountAttributes(newMount);

      const savedMount = await queryRunner.manager.save(newMount);

      await queryRunner.commitTransaction();

      return {
        success: true,
        message: `成功购买坐骑：${mountBase.name}，消耗${mountPrice}金币`,
        mountId: savedMount.id,
      };
    } catch (error: any) {
      await queryRunner.rollbackTransaction();
      this.logger.error(
        `购买坐骑失败: characterId=${characterId}, mountBaseId=${mountBaseId}`,
        error
      );
      return {
        success: false,
        message: error?.message || "购买坐骑失败",
      };
    } finally {
      await queryRunner.release();
    }
  }


  /**
   * 更新坐骑属性（基于等级和基础数据）
   * 使用公式：(当前转职等级上限属性 - 初始属性) / 当前转职等级上限 * 当前等级取整数
   */
  private updateMountAttributes(mount: CharacterMountEntity): void {
    if (!mount.mountBase) {
      return;
    }

    const base = mount.mountBase;
    const level = mount.level;
    const transLevel = mount.transLevel || 0;

    // 获取坐骑属性配置
    const config = getMountAttributeConfig(base.name);
    if (!config) {
      // 如果没有配置，使用默认计算方式
      this.calculateDefaultAttributes(mount, base, level, transLevel);
      return;
    }

    // 根据转职等级确定最大等级
    let maxLevel: number;
    switch (transLevel) {
      case 0: // 未转
        maxLevel = PROMOTION_MAX_LEVELS.notPromoted;
        break;
      case 1: // 一转
        maxLevel = PROMOTION_MAX_LEVELS.firstPromotion;
        break;
      case 2: // 二转
        maxLevel = PROMOTION_MAX_LEVELS.secondPromotion;
        break;
      case 3: // 三转
        maxLevel = PROMOTION_MAX_LEVELS.thirdPromotion;
        break;
      default:
        maxLevel = PROMOTION_MAX_LEVELS.notPromoted;
    }

    // 计算各属性
    if (config.attributes.ap) {
      const apConfig = config.attributes.ap;
      const maxAp = this.getMaxAttributeByTransLevel(apConfig.maxLevels, transLevel);
      const initialAp = typeof (base as any).apIni === "number" ? (base as any).apIni : apConfig.initial;
      mount.currentAp = calculateMountAttribute(initialAp, maxAp, maxLevel, level);
    } else {
      mount.currentAp = base.apIni;
    }

    if (config.attributes.hp) {
      const hpConfig = config.attributes.hp;
      const maxHp = this.getMaxAttributeByTransLevel(hpConfig.maxLevels, transLevel);
      const initialHp = typeof (base as any).hpIni === "number" ? (base as any).hpIni : hpConfig.initial;
      mount.currentHp = calculateMountAttribute(initialHp, maxHp, maxLevel, level);
    } else {
      mount.currentHp = base.hpIni;
    }

    if (config.attributes.sp) {
      const spConfig = config.attributes.sp;
      const maxSp = this.getMaxAttributeByTransLevel(spConfig.maxLevels, transLevel);
      const initialSp = typeof (base as any).spIni === "number" ? (base as any).spIni : spConfig.initial;
      mount.currentSp = calculateMountAttribute(initialSp, maxSp, maxLevel, level);
    } else {
      mount.currentSp = base.spIni;
    }

    if (config.attributes.speed) {
      const speedConfig = config.attributes.speed;
      const maxSpeed = this.getMaxAttributeByTransLevel(speedConfig.maxLevels, transLevel);
      // 速度属性存储在 currentMp 字段中（根据现有数据结构）
      const initialSpeed = typeof (base as any).mpIni === "number" ? (base as any).mpIni : speedConfig.initial;
      mount.currentMp = calculateMountAttribute(initialSpeed, maxSpeed, maxLevel, level);
    } else {
      mount.currentMp = base.mpIni;
    }
  }

  /**
   * 根据转职等级获取最大属性值
   */
  private getMaxAttributeByTransLevel(maxLevels: any, transLevel: number): number {
    switch (transLevel) {
      case 0: return maxLevels.notPromoted;
      case 1: return maxLevels.firstPromotion;
      case 2: return maxLevels.secondPromotion;
      case 3: return maxLevels.thirdPromotion;
      default: return maxLevels.notPromoted;
    }
  }

  /**
   * 默认属性计算方式（用于没有配置的坐骑）
   */
  private calculateDefaultAttributes(mount: CharacterMountEntity, base: any, level: number, transLevel: number): void {
    let maxLevel: number;
    let maxAp: number, maxHp: number, maxMp: number, maxSp: number;

    switch (transLevel) {
      case 0: // 未转
        maxLevel = 100;
        maxAp = base.ap;
        maxHp = base.hp;
        maxMp = base.mp;
        maxSp = base.sp;
        break;
      case 1: // 一转
        maxLevel = 120;
        maxAp = base.ap * 1.2;
        maxHp = base.hp * 1.2;
        maxMp = base.mp * 1.2;
        maxSp = base.sp * 1.2;
        break;
      case 2: // 二转
        maxLevel = 140;
        maxAp = base.ap * 1.4;
        maxHp = base.hp * 1.4;
        maxMp = base.mp * 1.4;
        maxSp = base.sp * 1.4;
        break;
      case 3: // 三转
        maxLevel = 160;
        maxAp = base.ap * 1.6;
        maxHp = base.hp * 1.6;
        maxMp = base.mp * 1.6;
        maxSp = base.sp * 1.6;
        break;
      default:
        maxLevel = 100;
        maxAp = base.ap;
        maxHp = base.hp;
        maxMp = base.mp;
        maxSp = base.sp;
    }

    mount.currentAp = this.calculateAttribute(base.apIni, maxAp, maxLevel, level);
    mount.currentHp = this.calculateAttribute(base.hpIni, maxHp, maxLevel, level);
    mount.currentMp = this.calculateAttribute(base.mpIni, maxMp, maxLevel, level);
    mount.currentSp = this.calculateAttribute(base.spIni, maxSp, maxLevel, level);
  }

  /**
   * 计算坐骑属性
   * 公式：(当前转职等级上限属性 - 初始属性) / 当前转职等级上限 * 当前等级取整数
   */
  private calculateAttribute(
    initialValue: number,
    maxValue: number,
    maxLevel: number,
    currentLevel: number
  ): number {
    const levelRatio = Math.floor(currentLevel) / maxLevel;
    return Math.floor(initialValue + (maxValue - initialValue) * levelRatio);
  }
}
